package cmpe273.proj1.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import cmpe273.proj1.utilities.Utilities;

//http://balusc.blogspot.com/2008/07/dao-tutorial-data-layer.html
public class Course implements Serializable {
	//public constants
	public final static double COURSE_COST = 425.28;
	public final static int MAX_LENGTH_COURSENAME = 40;
	public final static int MAX_LENGTH_SECTION = 40;
	public final static int MAX_LENGTH_TIMES = 40;
	public final static int MAX_LENGTH_LOCATION = 40;
	
	//private members
	private Long id;
	private String courseName;
	private String section;
	private String times;
	private String location;
	
	//constructors
	public Course() {
		this.id = null;
		this.courseName = "";
		this.section = "";
		this.times = "";
		this.location = "";
	}
	
	public Course(Long id, String courseName, String section, String times, String location) {
		this.id = id;
		this.courseName = courseName;
		this.section = section == null ? "" : section;
		this.times = times == null ? "" : times;
		this.location = location == null ? "" : location;
	}
	
	//accessors
	public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
    
	public String getCourseName() {
		return courseName;
	}
	public void setCourseName(String courseName) {
		this.courseName = courseName;
	}
	public String getSection() {
		return section;
	}
	public void setSection(String section) {
		this.section = section;
	}
	public String getTimes() {
		return times;
	}
	public void setTimes(String times) {
		this.times = times;
	}
	public String getLocation() {
		return location;
	}
	public void setLocation(String location) {
		this.location = location;
	}
	
	//json utilities
	public boolean loadCourse(JSONObject jsonObj) {
		try {
			this.courseName = jsonObj.getString("courseName");
			this.section = jsonObj.getString("section");
			this.times = jsonObj.getString("times");
			this.location = jsonObj.getString("location");
		} catch (JSONException e) {
			System.out.println("Invalid Course jsonObj: " + jsonObj.toString());
			return false;
		}
		return true;
	}
	
	public boolean loadCourse(String jsonString) {
		try {
			JSONObject obj = new JSONObject(jsonString);
			
			return loadCourse(obj);
		} catch (JSONException e) {
			System.out.println("Invalid Course jsonString: " + jsonString);
			return false;
		}
	}
	
	public String toJsonString() {
		String rtn  = "{\"courseName\":\"" + courseName + "\", \"section\":\"" + section + "\", \"times\":\"" + times + "\", \"location\":\"" + location + "\"}";
		return rtn;
	}
	
	public JSONObject toJsonObject()
	{
		return Utilities.toJsonObject(this.toJsonString());
	}
	
	public static List<Course> toCourseList(JSONArray taughtCourses) throws JSONException {
		List<Course> rtn = new ArrayList<Course>(taughtCourses.length());
		Course toAdd;
		for(int idx = 0; idx < taughtCourses.length(); idx++) {
			toAdd = new Course();
			if(toAdd.loadCourse(taughtCourses.getJSONObject(idx)))
				rtn.add(toAdd);
		}
		
		return rtn;
	}
	
	public static String toJsonArray(List<Course> taughtCourses) {
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		for(Course c : taughtCourses) {
			sb.append(c.toJsonString());
			sb.append(",");
		}
		if(sb.toString().endsWith(","))
			return sb.toString().substring(0, sb.toString().length() - 2) +"]";
		sb.append("]");
		return sb.toString();
	}
	
	//validation utilities
	public String validate() {
		StringBuilder sb = new StringBuilder();
		if(courseName.length() > MAX_LENGTH_COURSENAME)
			sb.append(String.format(Utilities.STRING_LENGTH_ERROR, "Coursename", MAX_LENGTH_COURSENAME));
		if(section.length() > MAX_LENGTH_SECTION)
			sb.append(String.format(Utilities.STRING_LENGTH_ERROR, "Section", MAX_LENGTH_SECTION));
		if(times.length() > MAX_LENGTH_TIMES)
			sb.append(String.format(Utilities.STRING_LENGTH_ERROR, "Times", MAX_LENGTH_TIMES));
		if(location.length() > MAX_LENGTH_LOCATION)
			sb.append(String.format(Utilities.STRING_LENGTH_ERROR, "Location", MAX_LENGTH_LOCATION));
		return sb.toString();
	}
	
	//Serializable Overrides
	private static final long serialVersionUID = 1L;
	
	/**
     * The user ID is unique for each Course. So this should compare Course by ID only.
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object other) {
        return (other instanceof Course) && (id != null)
             ? id.equals(((Course) other).id)
             : (other == this);
    }

    /**
     * The user ID is unique for each Course. So Course with same ID should return same hashcode.
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        return (id != null) 
             ? (this.getClass().hashCode() + id.hashCode()) 
             : super.hashCode();
    }

    /**
     * Returns the String representation of this Course. Not required, it just pleases reading logs.
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return String.format("Course[id=%d,courseName=%s,section=%s,times=%s,location=%s]", 
            id, courseName, section, times, location);
    }
}
